package org.orm.hsc;

import com.domain.Car;
import org.orm.hsc.exceptions.SQLFormatException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author
 * @date 2025-04-16
 * @Description 提供与数据库交互相关的api 提供的方法只支持新规则sql
 */
public class SqlSession {

    private JdbcExecutor executor;

    /**
     * 如果是无参构造方法
     * 默认是手动提交事务
     */
    public SqlSession() {
        this(false);
    }

    /**
     * 提供一个方法来设置是否自动提交事务
     *
     * @param isAutoCommit
     */
    public SqlSession(boolean isAutoCommit) {
        this.executor = new JdbcExecutor(isAutoCommit);
    }

    //---------------------加入configuration-------------------------------

    private Configuration configuration  ;
    public SqlSession(Configuration configuration) {
        this(configuration,false);
    }

    public SqlSession(Configuration configuration,boolean isAutoCommit) {
        this.configuration = configuration ;
        this.executor = new JdbcExecutor(configuration,isAutoCommit);
    }

    /**
     * 实现数据保存后，需要获得自增主键值，并将其存储在paramObj对象的指定属性中
     *
     * @param sql
     * @param paramObj
     * @param propertyName
     * @return
     */
    public int insert(String sql, Object paramObj, String propertyName) {
        // 1. 先执行insert语句
        int count = insert(sql, paramObj, true);
        // 处理关于自增主键值问题
        Long generatedKey = executor.getGeneratedKey();
        //利用反射实现复制 将
        //setCno(int cno) , setCno(long cno) , setCno(short cno)
        //因为set方法的参数类型不确定，所以不能通过名字直接找到方法
        //遍历查找
        String methodName;
        if (propertyName.length() == 1) {
            methodName = "set" + propertyName.toUpperCase();
        } else {
            methodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        }
        Method[] methods = paramObj.getClass().getMethods();
        for (Method method : methods) {
            String mname = method.getName();
            // 判断当前方法是否是set方法
            if (mname.equals(methodName)) {
                // 找到对应设置主键的set方法
                // 反射获取当前set 方法的参数类型 一般情况下 setCno(Long cno) 只有一个参数
                Class<?> parameterType = method.getParameterTypes()[0];
                try {
                    if (parameterType == short.class || parameterType == Short.class){
                        method.invoke(paramObj, generatedKey.shortValue());
                    }
                    if (parameterType == int.class || parameterType == Integer.class) {
                        method.invoke(paramObj, generatedKey.intValue());
                    }
                    if (parameterType == long.class || parameterType == Long.class) {
                        method.invoke(paramObj, generatedKey);
                    }
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
                // 设置成功 跳出循环 优化性能
                break;
            }

        }
        // 这样我们就设置好了主键值放回对象中 并且返回
        return count;

    }

    public int insert(String sql, Object paramObj, boolean isGeneratedKey) {
        // 如果是insert语句
        if ("insert".equalsIgnoreCase(sql.trim().substring(0, 6))) {
            // 直接掉用JdbcExecutor 的doUpdate方法
            return executor.doUpdate(sql, isGeneratedKey, paramObj);
        }
        //代码至此，说明不是一个insert语句，不执行。 需要给使用者反馈（异常）
        throw new SQLFormatException("not a insert statement : " + sql);
    }

    public void commit() {


    }

    public <T> List<T> selectList(String sql  , Class<T> rowType) {
        return selectList(sql,null,rowType);
    }

    public <T> List<T> selectList(String sql , Object paramObj , Class<T> rowType ){
        if ("select".equalsIgnoreCase(sql.trim().substring(0,6))){
            return executor.doQuery(sql,rowType,paramObj);
        }
        throw new SQLFormatException("not a select statement : " + sql) ;
    }
}
